/*****************************************************************************
 * $Workfile:: labview.c                                                     $
 * $Revision:: 19                                                            $
 * $JustDate::  3/21/12                                                      $
 *
 *      GENIE V
 *      labview parameter programming interface
 *****************************************************************************/

#include "common.h"
#include "display.h"
#include "eeprom.h"
#include "main.h"
#include "nvm.h"
#include "curve.h"
#include "control.h"
#include "fet.h"
#include "switches.h"
//#include "test.h"
#include "calibrate_load_sensing.h"

#define ACK 6           // Labview protocol
#define NACK 21         // Labview protocol

typedef enum
{
   eACK
   , eNACK
   , eSEND
   , eNORESPONSE
   , eREINIT
} eStatus_t;

typedef enum
{
   eBAUD_9600    = 68
   , eBAUD_19200  = 67
   , eBAUD_38400  = 66
   , eBAUD_57600  = 7
   , eBAUD_115200 = 3
} BAUD_e;


#define MAX_DATA_LEN (128 + 4)  // 4 byte address and 128 byte of flash buffer

typedef struct
{
   UINT8 bDevice;
   UINT8 bCommand;
   UINT8 bLength;
} head_t;


typedef struct
{
   head_t header;
   UINT8 abData[ MAX_DATA_LEN];
   UINT16 check_sum;
} packet_t;

#define MAX_PACKET_LEN sizeof( packet_t)
#define PACKET_OVERHEAD_LEN  (HEADER_LEN + CHECK_SUM_LEN) //(MAX_PACKET_LEN - MAX_DATA_LEN)
#define CHECK_SUM_LEN   sizeof( ((packet_t * )0)->check_sum)
#define HEADER_LEN  sizeof( head_t)
#define HIBYTE(w)   ((UINT8) (((UINT16) (w) >> 8) & 0xFF))
#define LOBYTE(w)   ((UINT8) (w))

typedef enum
{
   eINIT = 0
   , eFINISH_INIT
   , eRECEIVING
   , eRECEIVED
   , eTRANSMITTING
   , eTRANSMITED
   , eTEST
   , eFINISH_INIT2
   , eRECEIVING1
} xfer_e;


static struct
{
   UINT8 abData[ MAX_PACKET_LEN];
   UINT16 wLength;
   xfer_e eState;
   UINT16 ix;
   UINT8 bSymb;
   UINT8 xor_bit;
   UINT8  bBaud;
   BAUD_e eBaud;
   UINT8 bAncor;
   UINT8 bFrameErrorCount;
   struct
   {
      UINT8 filler : 5;
      UINT8 packet_transmitting : 1;
      UINT8 packet_received : 1;
      UINT8 packet_receiving : 1;
   } flag;
} lbv_xfer;


#define PACKET_DATA ((UINT8 *)&lbv_xfer.abData[ 3])
#define DATA_LENGTH (lbv_xfer.abData[ 2])
#define SET_HEADER(To,CoMaNd,LeNgTh)    \
{   \
    lbv_xfer.abData[ 0] = To;   \
    lbv_xfer.abData[ 1] = CoMaNd;   \
    lbv_xfer.abData[ 2] = LeNgTh;   \
}

#define SET_RATE(RaTe)  {lbv_xfer.eBaud = RaTe;}
/*
 * destiantion addresees
 */
#define TO_ECU 0
#define TO_PLATFORM_CONTROLLER 1
#define TO_LABVIEW  2  // This is the Labview programmer
#define TO_GROUND_PANEL 3
/*
 * commands/message IDs
 */
#define  CID_FlashProgramStart      0   // Labview to BootLoader
#define  CID_FlashProgramData       1   // labview to BootLoader
#define  CID_FlashEraseBlock        2   // Labview to BootLoader
#define  CID_FlashProgramStop       3   // Labview to BootLoader
#define  CID_FlashRead              4   // Labview to BootLoader
#define  CID_SetBaudRate            5   // ECU to Platfrom Application
#define  CID_AppNormalModeReset     6   // Labview to Application/BootLoader
#define  CID_GetPlatformType        7   // ?
#define  CID_SetParameters          8   // Labview to ECU
#define  CID_GetParameters          9   // Labview to ECU
#define  CID_RestoreDefaults        10  // Labview to ECU
#define  CID_GetApplicationRev      11  // Labview to ECU
#define  CID_GetBootRev             12  // Labview to ECU
#define  CID_PacketACK              13  // This is a response packet . It is never used.
#define  CID_PacketNAK              14  // This is a response packet. It is never used
#define  CID_IsAlive                15  // Send a packet ack if this is rec'd. It is never used.
#define  CID_BootModeReset          16  // Labview to Application/BootLoader
#define  CID_AppParameterModeReset  17  // ??
#define  CID_PlatformIO             18  // AB38 group ECU to Platfrom
#define  CID_GetSystemStates        19    // Used on ECU only
#define  CID_SetSystemStates        20    // Used on ECU only
#define  CID_GetAppRevForECU        21    // ECU to platform
#define  CID_GroundIOnew            22  // ECU to/from Ground TL50 group
#define  CID_PlatformIOnew          23  // ECU to/from Platfrom TL50 group
#define  CID_SetOptions             29  // Labview to ECU
#define  CID_GetOptions             30  // Labview to ECU


#define MY_ID   0

#define PUT(x)  { vSciSentByte(x); }

typedef eStatus_t (* callback_t)(void);

static eStatus_t Labview_GetBootRev(void);         // 12 CID_GetBootRev
static eStatus_t Labview_GetAppRev(void);          // 11 CID_GetApplicationRev
static eStatus_t Labview_BootModeReset(void);      // 16 CID_BootModeReset
static eStatus_t Labview_AppModeReset(void);       // 6 CID_AppNormalModeReset
static eStatus_t Labview_SetBaudRate(void);        // 5  CID_SetBaudRate
static eStatus_t Labview_IsAlive(void);            // 15 CID_IsAlive
static eStatus_t CallBack_Empty(void);             //    Left
static eStatus_t Labview_GetPlatformType(void);    // 7 CID_GetPlatformType
static eStatus_t Labview_GetParameters(void);      // 9 CID_GetParameters
static eStatus_t Labview_SetParameters(void);      // 8 CID_SetParameters
static eStatus_t Labview_RestoreDefaults(void);    // 10 CID_RestoreDefaults
static eStatus_t Labview_GetSystemStates(void);      // 19 CID_GetSystemStates
static eStatus_t Labview_SetSystemStates(void);      // 20 CID_SetSystemStates
//static eStatus_t Labview_GetOptions( void );
//static eStatus_t Labview_SetOptions( void );
static eStatus_t Labview_CheckEeprom(void);          // 21 CID_CheckEeprom
static eStatus_t Labview_CheckDisplay(void);      // 22 CID_CheckDisplay

static callback_t const process[ 32] =
{
   CallBack_Empty,  //0 CID_FlashProgramStart
   CallBack_Empty, //1 CID_FlashProgramData
   CallBack_Empty, //2 CID_FlashEraseBlock
   CallBack_Empty,     //3
   CallBack_Empty,     //4 CID_FlashRead      debug
   Labview_SetBaudRate, //5
   Labview_AppModeReset,//6
   Labview_GetPlatformType, //7
   Labview_SetParameters, //8 CID_SetParameters
   Labview_GetParameters, //9 CID_GetParameters
   Labview_RestoreDefaults, //10 CID_RestoreDefaults
   Labview_GetAppRev,  //11
   Labview_GetBootRev, //12
   CallBack_Empty,     //13
   CallBack_Empty,     //14
   //    ,CallBack_Empty     //15
   Labview_IsAlive,    //15
   Labview_BootModeReset, //16
   Labview_AppModeReset,  //17
   CallBack_Empty,     //18
   Labview_GetSystemStates,     //19
   Labview_SetSystemStates,  //20
   //    ,Labview_GetPlatformType    //20
   Labview_CheckEeprom,     //21
   Labview_CheckDisplay,     //22
   CallBack_Empty,    //23
   CallBack_Empty,     //24
   CallBack_Empty,     //25
   CallBack_Empty,     //26
   CallBack_Empty,     //27
   CallBack_Empty,     //28
   CallBack_Empty,  //Labview_SetOptions //29
   CallBack_Empty,  //Labview_GetOptions //30
   CallBack_Empty,     //31
};

static struct
{
   UINT8 bRate;
   UINT8 bCount;
   UINT8 bLiftType;
   UINT8 fDot: 1;
} LBV_Main;


static UINT8 m_ErrorCode = 0;


// Local Function Prototypes
static void lbv_serial_init(BAUD_e eBaud);
static void lbv_serial(void);



/*******************************************************************************
 *
 * PROCEDURE:    lbv_main()
 *
 * DESCRIPTION: Labview programmer interface task.
 *              It is invoked if boot code set variable BootFlasg to APP_MODE_LABVIEW.
 *              Boot code detects the spesial case of chassis fault ( code 12)
 *              and waits for labview. If labview commanded to load paraemter - application mode reset -
 *              the boot code indirectly calls lbv_main().
 *              It is an infint loop that has no interaction to main control loop.
 *
 * VARIABLE NAME    R/W DESCRIPTION
 * ---------------- --- --------------------------------------------------------
 ******************************************************************************/

void
lbv_main(void)
{

#define PET_WATCHDOG     {R_WDT_Restart();}
#define RX_ENABLE   {vSetStatusSciRxEn(0);}//{IO.PDR7.BIT.B5 = 0;}

   RX_ENABLE;

   LBV_Main.bLiftType = 15; // default set to small scissors
   MAIN_Data.bPCModeFlag = 1;

   lbv_serial_init(eBAUD_9600);
   INTERRUPTS_ENABLE;

   while(1)     //
   {
      lbv_serial();
      while(TIMER_Data.bSystemCycles)
      {
         TIMER_Data.bSystemCycles = 0;
         LBV_Main.bCount++;
         // update display
         if(LBV_Main.bRate)
         {
            LBV_Main.bRate--;
         }
         else
         {
            LBV_Main.bRate = 25;        //250 millisecond

            if(m_ErrorCode == 0)
            {
               Display.field.bSevenLeft = Seg7_Asc[ 'P'];
               Display.field.bSevenRight  = Seg7_Asc[ 'C'];
               Display.led.pd_r = (LBV_Main.fDot) ? 1 : 0;

               LBV_Main.fDot = !LBV_Main.fDot;
            }
            else
            {
               ECU_HEX(m_ErrorCode);
            }
            update_leds();
         }
      }

      PET_WATCHDOG;
   }
}


void lbv_serial_init(BAUD_e eBaud)
{
   lbv_xfer.eBaud = eBaud;
}


void lbv_serial(void)
{
   switch(lbv_xfer.eState)
   {
      default:

      /*
       * The perpose of the state is to initialize the
       * serial interface.
       */
      case eINIT:
         /*
         IO.PMR1.BIT.TXD = 1;   // Enable p22 as TxD
         SCI3.SCR3.BYTE = 0;     // Disable receiver and transmitter
         // Clear all errors, and trasmit/receive flags.
         SCI3.SMR.BYTE = 0;           // Set Async, 8Bit, NO Parity, 1 Stop, MP mode disabled,
         // Set Clock devider n = 0;
         SCI3.BRR  = lbv_xfer.eBaud; // Initialize Baud Rate
         */
         R_UART0_Start();
         lbv_xfer.eState = eRECEIVING1;

         break;

      /*
       * This state clears the recieve hardware after transmition
       * or initialization. The hardware uses half-duplex line and receiver
       * gets all transmit data back with delay up to a few microsecond.
       * this state must be called with small delay to dump loop-back data and
       * clear error flags.
       */
      case eRECEIVING1:
         lbv_xfer.eState = eRECEIVING;
         //SCI3.SSR.BYTE &= ~0x38;  // clear oer,per,fer, and rdrf
         //lbv_xfer.bSymb  = SDR01L;  // it will clear RDRF bit in SCI3 SSR register.
         break;

      /*
       * It parces the psuedo hdlc like protocol and save packet in receive
       * buffer. if packet received eRECEIVED state is initiated.
       * The packet is consisted in seqence of bytes:
       *  _packet_start(0x7e)_ _device_  _packet_type_ _packet_length_  _packet_data_ .. _packet_data_ _packet_control_sum_
       * the packet is always starts from 0x7e.
       * A 0x7E symbol is _packet_start
       * A0 x7D symbol is delimeter for special symbols such as 0x7e.
       * the symbol 0x7e is transimitted as 0x7d 0x5e
       * the symbol 0x7e is transmitted as 0x7d 0x5d
       * and so on.
       */
      case eRECEIVING:
         /*
         if ( 0 != (SCI3.SSR.BYTE & 0x38) ) // OER, PER, FER
         {
             SCI3.SSR.BYTE &= ~0x38;  // clear only processed errors;
             lbv_xfer.bFrameErrorCount++;

         #ifdef MULTI_BAUD_RATES
             if ( lbv_xfer.bFrameErrorCount > 3)
             {
                 lbv_xfer.bFrameErrorCount = 0;
                 lbv_xfer.flag.packet_receiving = 0;
                 lbv_xfer.eState = eINIT;
                 if ( eBAUD_9600 == lbv_xfer.eBaud)
                 {
                     lbv_xfer.eBaud = eBAUD_19200;
                 }
                 else
                 {
                     lbv_xfer.eBaud = eBAUD_9600;
                 }
             }
         #endif

             lbv_xfer.bSymb  = SCI3.RDR;  // it will clear RDRF bit in SCI3 SSR register.
         }
         */
         if(u8IsRxFull()) //( 1 == SCI3.SSR.BIT.RDRF)
         {
            lbv_xfer.bSymb  = u8SciGetByte();  // it will clear RDRF bit in SCI3 SSR register.

            if(0x7e == lbv_xfer.bSymb)
            {
               lbv_xfer.wLength = MAX_PACKET_LEN;
               lbv_xfer.ix = 0;
               lbv_xfer.xor_bit = 0;
               lbv_xfer.flag.packet_receiving = 1;
            }
            else if(0x7d == lbv_xfer.bSymb)
            {
               lbv_xfer.xor_bit = 0x20;
            }
            else if(1 == lbv_xfer.flag.packet_receiving)
            {
               lbv_xfer.bSymb = lbv_xfer.bSymb ^ lbv_xfer.xor_bit;
               lbv_xfer.xor_bit = 0;

               lbv_xfer.abData[ lbv_xfer.ix++] = lbv_xfer.bSymb;

               if(3 == lbv_xfer.ix)
               {
                  lbv_xfer.wLength = lbv_xfer.bSymb + PACKET_OVERHEAD_LEN;
                  if(lbv_xfer.wLength > MAX_PACKET_LEN)   // device_id(1), command(1), length(1), data(32), check_Sum(2)
                  {
                     lbv_xfer.flag.packet_receiving = 0;
                  }
               }
               else if(lbv_xfer.ix >= lbv_xfer.wLength)
               {
                  lbv_xfer.eState = eRECEIVED;
                  lbv_xfer.flag.packet_receiving = 0;
               }
            }
         }
         break;

      /*
       * It validates the recieved packet.
       * It checks destination, packet control sum.
       * If packet is ok, it calls the function assosiated with _packet_type_
       */
      case eRECEIVED:
         {
            UINT16 wLength;
            UINT8 ix;
            UINT16 wCheckSum;
            head_t * pHead;
            eStatus_t eStatus;


            if(lbv_xfer.wLength  >= PACKET_OVERHEAD_LEN)
            {
               wLength = lbv_xfer.wLength - CHECK_SUM_LEN;
               wCheckSum = 0;

               for(ix = 0; ix < wLength; ix++)
               {
                  wCheckSum += lbv_xfer.abData[ ix];
               }

               wCheckSum ^= (lbv_xfer.abData[ ix++] << 8);
               wCheckSum ^= lbv_xfer.abData[ ix];

               pHead = (head_t *)&lbv_xfer.abData[ 0];

               // verify  check_sum
               if((MY_ID == pHead->bDevice) && !wCheckSum)
               {
                  lbv_xfer.bFrameErrorCount = 0;
                  // process received packet
                  eStatus = process[pHead->bCommand & 0x1F]();

                  // packet is formed by process()
                  // response to received packet as needed, refer to eStatus
                  // the data are copied by process()
                  // the length is set by process()

                  switch(eStatus)
                  {
                     case eSEND:
                        wLength = pHead->bLength + HEADER_LEN;
                        wCheckSum = lbv_xfer.abData[ 0];
                        for(ix = 1; ix < wLength; ix++)
                        {
                           wCheckSum += lbv_xfer.abData[ ix];
                        }
                        lbv_xfer.abData[ ix++] = (wCheckSum >> 8);
                        lbv_xfer.abData[ ix]   = wCheckSum & 0xff;
                        lbv_xfer.wLength = wLength + CHECK_SUM_LEN;
                        lbv_xfer.bSymb = lbv_xfer.abData[ 0];
                        lbv_xfer.ix = 0;
                        lbv_xfer.eState = eTRANSMITTING;

                        PUT(0x7e);
                        return;
                     case eACK:
                        PUT(ACK);
                        lbv_xfer.eState = eTRANSMITED;
                        return;
                     case eNACK:
                        PUT(NACK);
                        lbv_xfer.eState = eTRANSMITED;
                        return;
                     default:
                     case eNORESPONSE:
                        break;
                  }
               }
               else
               {
                  // count bad packets.
               }
            }
            else
            {
               // count bad packets.
            }
         }
         lbv_xfer.eState = eRECEIVING;
         break;

      /*
       * It transmiited packet and insert special symbols on fly.
       */
      case eTRANSMITTING:
         if(u8IsTxReady()) //( SCI3.SSR.BIT.TDRE)
         {
            if(0x7e == lbv_xfer.bSymb
               || 0x7d == lbv_xfer.bSymb)
            {
               lbv_xfer.bSymb ^= 0x20;
               PUT(0x7d);
            }
            else
            {
               PUT(lbv_xfer.bSymb);
               lbv_xfer.ix++;
               if(lbv_xfer.ix < lbv_xfer.wLength)
               {
                  lbv_xfer.bSymb = lbv_xfer.abData[ lbv_xfer.ix];
               }
               else
               {
                  lbv_xfer.eState = eTRANSMITED;
               }
            }
         }
         break;

      /*
       * it wait for transmittion to finish.
       * it reinit system if the speed cahnge is requested.
       */
      case eTRANSMITED:
         if(u8IsTransmitted()) //( 1 == SCI3.SSR.BIT.TEND)
         {
            lbv_xfer.eState = eRECEIVING1;
         }

         break;
   }
}


/*******************************************************************************
 *
 * PROCEDURE:    Labview_GetPlatformType()
 *
 * DESCRIPTION: It returns the last lift type and all supported lift types.
 *              NOte: There is no default types.
 *
 * VARIABLE NAME    R/W DESCRIPTION
 * ---------------- --- --------------------------------------------------------
 ******************************************************************************/

eStatus_t
Labview_GetPlatformType(void)
{
   UINT8 * pb;

   pb   = PACKET_DATA;

   pb[ 0]  = LBV_Main.bLiftType;
   pb[ 1]  = 14;
   pb[ 2]  = 15;
   pb[ 3]  = 16;
   pb[ 4]  = 17;

   SET_HEADER(TO_LABVIEW, CID_GetPlatformType, 5);

   return eSEND;
}

/*******************************************************************************
 *
 * PROCEDURE:    Labview_GetBootRev()
 *
 * DESCRIPTION: It returns the boot code revision and descrition string.
 *
 * VARIABLE NAME    R/W DESCRIPTION
 * ---------------- --- --------------------------------------------------------
 ******************************************************************************/

eStatus_t
Labview_GetBootRev(void)
{
   UINT8 ix;
   UINT8 * pb;
   UINT8 * pbSw;

   pbSw = (UINT8 *)BootSWRevAddress;
   pb   = PACKET_DATA;

   for(ix = 0; ix < (MAX_DATA_LEN - 1) && 0 != *pbSw; ix++)
   {
      *pb++ = *pbSw++;
   }

   //    *pb  = 0;

   SET_HEADER(TO_LABVIEW, CID_GetBootRev, ix);

   return eSEND;
}

/*******************************************************************************
 *
 * PROCEDURE:    Labview_GetAppRev()
 *
 * DESCRIPTION: It returns the application code revision and descrition string.
 *
 * VARIABLE NAME    R/W DESCRIPTION
 * ---------------- --- --------------------------------------------------------
 ******************************************************************************/

eStatus_t
Labview_GetAppRev(void)
{
   UINT8 ix;
   UINT8 * pb;
   UINT8 const * pbSw;


   pbSw = (UINT8 *)&IMAGE_Descr.szName[0];

   pb   = PACKET_DATA;

   ix = 0;

   while(ix < MAX_DATA_LEN && 0 != *pbSw)
   {
      ix++;
      *pb++ = *pbSw++;
   }

   SET_HEADER(TO_LABVIEW, CID_GetApplicationRev, ix);

   return eSEND;
}

/*******************************************************************************
 *
 * PROCEDURE:    Labview_BootModeReset()
 *
 * DESCRIPTION: It set BootCode variable shared between app and boot code
 *              and reset micro.
 *
 * VARIABLE NAME    R/W DESCRIPTION
 * ---------------- --- --------------------------------------------------------
 ******************************************************************************/

eStatus_t
Labview_BootModeReset(void)
{  // it never return
   BootFlag = BOOT_MODE_MAGIC;
   for(;;)
   {
//    IO.PCR2 = 0x1;        // Set Port 2 bit 0 to an output
//    IO.PDR2.BIT.B0 = 0;     // Issue a master reset to the DS1705 to reset micro
   }
// return eNORESPONSE;
}

/*******************************************************************************
 *
 * PROCEDURE:    Labview_AppModeReset()
 *
 * DESCRIPTION: It is ignored.
 *
 * VARIABLE NAME    R/W DESCRIPTION
 * ---------------- --- --------------------------------------------------------
 ******************************************************************************/


eStatus_t
Labview_AppModeReset(void)
{  // it never return
#if 0
   BootFlag = APP_MODE_MAGIC;
   IO.PCR2 = 0x1;        // Set Port 2 bit 0 to an output
   IO.PDR2.BIT.B0 = 0;     // Issue a master reset to the DS1705 to reset micro
#endif
   return eNORESPONSE;
}

/*******************************************************************************
 *
 * PROCEDURE:    Labview_SetBaudRate()
 *
 * DESCRIPTION: It set serial interface speed.
 *              Note. the acknowledge is sent an old speed.
 *
 * VARIABLE NAME    R/W DESCRIPTION
 * ---------------- --- --------------------------------------------------------
 ******************************************************************************/

eStatus_t
Labview_SetBaudRate(void)
{
   UINT8 bLength;
   //UINT8 * pb;

   //pb = PACKET_DATA;
   bLength = DATA_LENGTH;

   if(bLength >= sizeof(long))
   {
      /*
      switch ( *( long *)pb )
      {
          case  9600:
              SET_RATE( eBAUD_9600);
              return eACK;
          case  19200:
              SET_RATE( eBAUD_19200);
              return eACK;
      }*/
   }
   return eNACK;
}

/*******************************************************************************
 *
 * PROCEDURE:    Labview_IsAlive()
 *
 * DESCRIPTION: It supports an labview programmer internal bug.
 *
 * VARIABLE NAME    R/W DESCRIPTION
 * ---------------- --- --------------------------------------------------------
 ******************************************************************************/

eStatus_t
Labview_IsAlive(void)
{
   return eACK;
}

/*******************************************************************************
 *
 * PROCEDURE:    CallBack_Empty()
 *
 * DESCRIPTION: It is a template for packet command. The default handler.
 *
 * VARIABLE NAME    R/W DESCRIPTION
 * ---------------- --- --------------------------------------------------------
 ******************************************************************************/


eStatus_t
CallBack_Empty(void)
{
   return eNORESPONSE;
}

struct LBV_Curve
{
   UINT8   PosAdjustedMaxSpeed;
   UINT8   NegAdjustedMaxSpeed;
   UINT8   AccelCounts;
   UINT8   AccelTimeInterval;
   UINT8   DecelCounts;
   UINT8   DecelTimeInterval;

   UINT8   Break[4];
   UINT8   PosMotorSpeed[5];
   UINT8   NegMotorSpeed[5];

};


// 128 bytes
struct LBV_Parameter
{
   //    14 = Runabout
   //    15 = Slab small
   //    16 = Slab large
   //    17 = DC68

   UINT8 bLiftType;                    // 0.

   UINT8 bMagic;                       // 1,
#define LABVIEW_REV1   1
#define LABVIEW_REV2   2
   UINT8 bBrakeDelay;                  // 2, X_100 ( ie 20 is 2000 milliseond )
   UINT8 bCoilFaultDetectionPeriod;    // 3, X_10  ( ie 70 is 700 millisecond )
   UINT8 bSteeringOffDelay;            // 4, X_100
   UINT8 bDirectionDelay;              // 5, X_10
   UINT8 bMotorEnableDelay;            // 6, X_10
   UINT8 bOverloadStabilizationPeriod; // 7, X_100
   UINT8 bSteeringBoostPwm;            // 8, 0..100 percent
   UINT8 bNeutralSteeringPwm;          // 9, 0..100 percent
   UINT8 bChassisLiftUpPwm;            // 10,0..100 percent
   UINT8 bPlatformLiftUpMaxPwm;        // 11,0..100 percent
   UINT8 bJoystickOffsetCompensation;  // 12,0 .. 127 counts
   UINT8 bJoystickNeutralZone;         // 13,0 .. 127 counts

   // 10th volts. Offset 10volt is substracted. ie 27.7 => 177
   UINT8 bBatteryLevel1;               // 14,
   UINT8 bBatteryLevel2;               // 15,
   UINT8 bBatteryLevel3;               // 16,
   UINT8 bBatteryLevel4;               // 17,
   UINT8 bBatteryLevel5;               // 18,

   UINT8 bTiltBrakeDelay;              // 19, X_10
   UINT8 bLevelBrakeDelay;             // 20, X_10

   UINT8 bSpare1;
   UINT8 bSpare2;
   UINT8 bSpare3;
   UINT8 bSpare4;
   UINT8 bSpare5;

   struct LBV_Curve drive_fast_curve;  // fast drive stowed curve
   struct LBV_Curve drive_rised_curve; // very slow drive rized curve
   struct LBV_Curve lift_up_curve;     // lift only up curve
   struct LBV_Curve drive_slow_curve;  // slow drive stowed curve
   //    struct LBV_Curve steer_fast_curve;  // fast steer stowed curve
   struct LBV_Curve steer_rised_curve; // very slow steer rized curve
};


/*******************************************************************************
 *
 * PROCEDURE:    setup_to_lbv()
 *
 * DESCRIPTION: it copies internal curve structure to labview structure.
 *              positive and negative branches are duplicated.
 *
 * VARIABLE NAME    R/W DESCRIPTION
 * ---------------- --- --------------------------------------------------------
 ******************************************************************************/

static void
setup_to_lbv(struct LBV_Curve * pLbv,
             struct nvm_curve * pCurve)
{
   pLbv->Break[ 0] = pCurve->bIndex1;
   pLbv->Break[ 1] = pCurve->bIndex2;
   pLbv->Break[ 2] = pCurve->bIndex3;
   pLbv->Break[ 3] = pCurve->bIndex4;

   pLbv->PosMotorSpeed[ 0] = pCurve->bPwmPos1;
   pLbv->PosMotorSpeed[ 1] = pCurve->bPwmPos2;
   pLbv->PosMotorSpeed[ 2] = pCurve->bPwmPos3;
   pLbv->PosMotorSpeed[ 3] = pCurve->bPwmPos4;
   pLbv->PosMotorSpeed[ 4] = pCurve->bPwmPosMax;

   pLbv->NegMotorSpeed[ 0] = pCurve->bPwmNeg1;
   pLbv->NegMotorSpeed[ 1] = pCurve->bPwmNeg2;
   pLbv->NegMotorSpeed[ 2] = pCurve->bPwmNeg3;
   pLbv->NegMotorSpeed[ 3] = pCurve->bPwmNeg4;
   pLbv->NegMotorSpeed[ 4] = pCurve->bPwmNegMax;

   pLbv->AccelCounts         = pCurve->bAccelIncrement;
   pLbv->AccelTimeInterval   = pCurve->bPeriod;
   pLbv->DecelCounts         = pCurve->bDecelIncrement;
   pLbv->DecelTimeInterval   = pCurve->bPeriod;
   pLbv->PosAdjustedMaxSpeed = pCurve->bPwmPosAdjust;
   pLbv->NegAdjustedMaxSpeed = pCurve->bPwmNegAdjust;
}

/*******************************************************************************
 *
 * PROCEDURE:    Labview_GetParameters()
 *
 * DESCRIPTION: it converts internal parameter structure to labview structure
 *              and send it to labview.
 *
 * VARIABLE NAME    R/W DESCRIPTION
 * ---------------- --- --------------------------------------------------------
 ******************************************************************************/

eStatus_t
Labview_GetParameters(void)
{
   UINT8 * pb;
   struct nvm_lift_setup * pSetup;
   struct LBV_Parameter  * pLbv;
   //    UINT16 wControlSum;                 // 126, 127, sum  off all bytes



   pb   = PACKET_DATA;
   pLbv = (struct LBV_Parameter *)PACKET_DATA;

   if(!DATA_LENGTH)
   {
      return eNACK;
   }

   switch(*pb)    // lift typed
   {
      default:
         return eNACK;
      //break;
      case 6:     // lift type from last operation
         break;
      case 14:    // mini
      case 15:    // small slab
      case 16:    // large slab
      case 17:    // dc68
         LBV_Main.bLiftType = *pb;
         break;
   }

   switch(LBV_Main.bLiftType)    // lift typed
   {
      default:
      case 15:    // small slab
         pSetup = (struct nvm_lift_setup *)&small_slab_setup;
         break;
      case 14:    // mini
         pSetup = (struct nvm_lift_setup *)&electric1_setup;
         break;
      case 16:    // large slab
         pSetup = (struct nvm_lift_setup *)&electric3_setup;
         break;
      /*case 17:    // dc68
         pSetup = &electric2_setup;
         break;*/
   }

   if(EEPROM_OK == record_read(pSetup->bLiftType
                               , sizeof(struct nvm_lift_setup)
                               , (UINT8 *)&lift_setup)
      && IMAGE_Descr.szName[ 0] == lift_setup.bMajor
      && IMAGE_Descr.szName[ 1] == lift_setup.bMinor)
   {
      pSetup = &lift_setup;
   }

   pLbv->bLiftType                   = LBV_Main.bLiftType;
   pLbv->bMagic                      = LABVIEW_REV2;
   pLbv->bBrakeDelay                 = pSetup->bBrakeDelay;
   pLbv->bCoilFaultDetectionPeriod   = pSetup->bCoilFaultDetectionPeriod;
   pLbv->bSteeringOffDelay           = pSetup->bSteeringOffDelay;
   pLbv->bDirectionDelay             = pSetup->bDirectionDelay;
   pLbv->bMotorEnableDelay           = pSetup->bMotorEnableDelay;
   pLbv->bOverloadStabilizationPeriod = pSetup->bOverloadStabilizationPeriod;
   pLbv->bSteeringBoostPwm           = pSetup->bSteeringBoostPwm;
   pLbv->bNeutralSteeringPwm         = pSetup->bNeutralSteeringPwm;
   pLbv->bChassisLiftUpPwm           = pSetup->bChassisLiftUpPwm;
   pLbv->bPlatformLiftUpMaxPwm       = pSetup->bPlatformLiftUpMaxPwm;
   pLbv->bJoystickOffsetCompensation = pSetup->bJoystickOffsetCompensation;
   pLbv->bJoystickNeutralZone        = pSetup->bJoystickNeutralZone;
   pLbv->bBatteryLevel1              = pSetup->bBatteryLevel1;
   pLbv->bBatteryLevel2              = pSetup->bBatteryLevel2;
   pLbv->bBatteryLevel3              = pSetup->bBatteryLevel3;
   pLbv->bBatteryLevel4              = pSetup->bBatteryLevel4;
   pLbv->bBatteryLevel5              = pSetup->bBatteryLevel5;
   pLbv->bTiltBrakeDelay             = pSetup->bTiltBrakeDelay;
   pLbv->bLevelBrakeDelay            = pSetup->bLevelBrakeDelay;
   pLbv->bSpare1                     = pSetup->bSpare1;
   pLbv->bSpare2                     = pSetup->bSpare2;
   pLbv->bSpare3                     = pSetup->bSpare3;
   pLbv->bSpare4                     = pSetup->bSpare4;
   pLbv->bSpare5                     = pSetup->bSpare5;

   setup_to_lbv(&pLbv->drive_fast_curve,
                &pSetup->drive_fast_curve);

   setup_to_lbv(&pLbv->drive_rised_curve,
                &pSetup->drive_rised_curve);

   setup_to_lbv(&pLbv->lift_up_curve,
                &pSetup->lift_up_curve);

   //    setup_to_lbv( &pLbv->steer_fast_curve,
   //                  &pSetup->steer_fast_curve);

   setup_to_lbv(&pLbv->drive_slow_curve,
                &pSetup->drive_slow_curve);

   setup_to_lbv(&pLbv->steer_rised_curve,
                &pSetup->steer_rised_curve);

#define PARAMETER_LENGTH  (sizeof( struct LBV_Parameter))

   SET_HEADER(TO_LABVIEW, CID_GetParameters, (PARAMETER_LENGTH));

   return eSEND;
}


/*******************************************************************************
 *
 * PROCEDURE:    lbv_to_setup()
 *
 * DESCRIPTION: it converts labview curve structure to internal curve structure
 *              and check curve values. Only positive branch of labview is used.
 *
 * VARIABLE NAME    R/W DESCRIPTION
 * ---------------- --- --------------------------------------------------------
 ******************************************************************************/

static UINT8
lbv_to_setup(struct LBV_Curve * pLbv,
             struct nvm_curve * pCurve,
             UINT8 bPwmLimit,
             UINT8 bJoystickNeutralZone)
{
   pCurve->bIndex1 = pLbv->Break[ 0];
   pCurve->bIndex2 = pLbv->Break[ 1];
   pCurve->bIndex3 = pLbv->Break[ 2];
   pCurve->bIndex4 = pLbv->Break[ 3];

   pCurve->bPwmPos1   =   pLbv->PosMotorSpeed[ 0];
   pCurve->bPwmPos2   =   pLbv->PosMotorSpeed[ 1];
   pCurve->bPwmPos3   =   pLbv->PosMotorSpeed[ 2];
   pCurve->bPwmPos4   =   pLbv->PosMotorSpeed[ 3];
   pCurve->bPwmPosMax =   pLbv->PosMotorSpeed[ 4];

   pCurve->bPwmNeg1   =   pLbv->NegMotorSpeed[ 0];
   pCurve->bPwmNeg2   =   pLbv->NegMotorSpeed[ 1];
   pCurve->bPwmNeg3   =   pLbv->NegMotorSpeed[ 2];
   pCurve->bPwmNeg4   =   pLbv->NegMotorSpeed[ 3];
   pCurve->bPwmNegMax =   pLbv->NegMotorSpeed[ 4];


   pCurve->bAccelIncrement = pLbv->AccelCounts;
   pCurve->bPeriod         = pLbv->AccelTimeInterval;
   pCurve->bDecelIncrement = pLbv->DecelCounts;
   pCurve->bPwmPosAdjust      = pLbv->PosAdjustedMaxSpeed;
   pCurve->bPwmNegAdjust      = pLbv->NegAdjustedMaxSpeed;

   //
   // curve must be increasing
   //
   if(pCurve->bIndex1 <= pCurve->bIndex2
      && pCurve->bIndex2 <= pCurve->bIndex3
      && pCurve->bIndex3 <= pCurve->bIndex4
      && pCurve->bIndex4 <= (127 - bJoystickNeutralZone)
      && pCurve->bPwmPos1  <= pCurve->bPwmPos2
      && pCurve->bPwmPos2  <= pCurve->bPwmPos3
      && pCurve->bPwmPos3  <= pCurve->bPwmPos4
      && pCurve->bPwmPos4  <= pCurve->bPwmPosMax
      && pCurve->bPwmPosMax <= bPwmLimit
      && pCurve->bPwmNeg1  <= pCurve->bPwmNeg2
      && pCurve->bPwmNeg2  <= pCurve->bPwmNeg3
      && pCurve->bPwmNeg3  <= pCurve->bPwmNeg4
      && pCurve->bPwmNeg4  <= pCurve->bPwmNegMax
      && pCurve->bPwmNegMax <= bPwmLimit
      && pCurve->bPwmPosAdjust <= bPwmLimit
      && pCurve->bPwmNegAdjust <= bPwmLimit
      && pCurve->bPeriod > 0
      && pCurve->bPeriod <= 200
     )
   {
      return 0;
   }
   return 1;
}

/*
 * The only Battery Monitor uses the A/D converter.
 * It has its own filter and thus we don't need one here.
 * We might want to revisit the code later.
 */
UINT16
GetADValue(UINT8 ch)
{
   return u16GetADCResult(ch);
}

/*******************************************************************************
 *
 * PROCEDURE:    Labview_SetSystemStates()
 *
 * DESCRIPTION: Sets output states of the ECU for test.
 *
 * VARIABLE NAME    R/W DESCRIPTION
 * ---------------- --- --------------------------------------------------------
 ******************************************************************************/

eStatus_t
Labview_SetSystemStates(void)
{
   UINT8 * pb;

   pb = PACKET_DATA;

   if(!DATA_LENGTH)    // at least 1 byte
   {
      return eNACK;
   }

   LIFT_Data.hd_fet = (UINT16)(pb[ 1]) & 0x00ff;
   LIFT_Data.hd_fet = LIFT_Data.hd_fet << 8;
   LIFT_Data.hd_fet = LIFT_Data.hd_fet | ((UINT16)(pb[ 0]) & 0x00ff);
   //test 2A-ouput
   if(LIFT_Data.hd_fet == 0x5A5A)
   {
      vSetStatus2A(1);
      Fets.word = 0xB000;
   }
   //test others
   else
   {
      vSetStatus2A(0);
      Fets.word = LIFT_Data.hd_fet;
   }

   LIFT_Data.calc_pwm1 = pb[ 2];
   LIFT_Data.calc_pwm2 = pb[ 3];

   FET_Update();
   LIFT_Pwm();

   //    SET_HEADER( TO_LABVIEW, CID_SetSystemStates, 2);

   //    return eSEND;
   return eACK;
}

/*******************************************************************************
 *
 * PROCEDURE:    Labview_GetSystemStates()
 *
 * DESCRIPTION: Sends the present state of the ECU.
 *
 * VARIABLE NAME    R/W DESCRIPTION
 * ---------------- --- --------------------------------------------------------
 ******************************************************************************/

eStatus_t
Labview_GetSystemStates(void)
{
   UINT16 wTemp;
   UINT8 * pb;
   UINT8 ix;

   pb = PACKET_DATA;

   ix = 0;
   while(ix < 5)
   {
      if(TIMER_Data.bSystemCycles)
      {
         TIMER_Data.bSystemCycles = 0;
         switches();
         ix++;
      }
   }

   pb[ 0] = (UINT8)(SWITCH_Data.wSwitches.word & 0x00ff);
   pb[ 1] = (UINT8)(SWITCH_Data.wSwitches.word / 0x0100);

   wTemp = 0;//FET_Test( Fets.word);

   pb[ 2] = (UINT8)(wTemp & 0x00ff);
   pb[ 3] = (UINT8)(wTemp / 0x0100);

   wTemp = ~wTemp & Fets.word;
   pb[ 4] = (UINT8)(wTemp & 0x00ff);
   pb[ 5] = (UINT8)(wTemp / 0x0100);

   pb[ 6] = HIBYTE(GetADValue(1));
   pb[ 7] = HIBYTE(GetADValue(2));
   pb[ 8] = HIBYTE(GetADValue(4));
   pb[ 9] = 0;//HIBYTE(GetADValue(3));
   pb[10] = HIBYTE(GetADValue(0));

   SET_HEADER(TO_LABVIEW, CID_GetSystemStates, 11);

   return eSEND;
}

/*******************************************************************************
 *
 * PROCEDURE:    Labview_SetOptions()
 *
 * DESCRIPTION: it saves option flags in nvram.
 *
 * VARIABLE NAME    R/W DESCRIPTION
 * ---------------- --- --------------------------------------------------------
 ******************************************************************************/
/*
eStatus_t
Labview_SetOptions( void )
{
    UINT8 * pb;


    pb = PACKET_DATA;

    if ( !DATA_LENGTH)  // at least 1 byte
    {
        return eNACK;
    }

    if ( (EEPROM_OK != record_write_verify( RECORD_MAGIC_OPTION_1, 1, pb))
         && ( EEPROM_OK != record_write_verify( RECORD_MAGIC_OPTION_2, 1, pb)) )
    )
    {
        return eNACK;
    }

    return eACK;
}
*/
/*******************************************************************************
 *
 * PROCEDURE:    Labview_GetOptions()
 *
 * DESCRIPTION: it saves option flags in nvram.
 *
 * VARIABLE NAME    R/W DESCRIPTION
 * ---------------- --- --------------------------------------------------------
 ******************************************************************************/
/*
eStatus_t
Labview_GetOptions( void )
{
    UINT8 * pb;

    pb = PACKET_DATA;


    if ( EEPROM_OK != record_read( RECORD_MAGIC_OPTION_1, 1, pb++))
    {
        *pb = 0x1;       // set option fault time
    }
    else
    {
        *pb = 0;
    }

    SET_HEADER( TO_LABVIEW, CID_GetOptions, 2);

    return eSEND;
}

*/

/*******************************************************************************
 *
 * PROCEDURE:    Labview_SetParameters()
 *
 * DESCRIPTION: it copies labview  parameter structure to internal parameter structure
 *              and check values. if all values is ok, it saves parameters to eeprom.
 *
 * VARIABLE NAME    R/W DESCRIPTION
 * ---------------- --- --------------------------------------------------------
 ******************************************************************************/

eStatus_t
Labview_SetParameters(void)
{
   //    UINT8   bRisedPwmLimit;
   UINT8 * pb;
   struct LBV_Parameter  * pLbv;


   pb = PACKET_DATA;
   pLbv = (struct LBV_Parameter *) PACKET_DATA;

   if(!DATA_LENGTH)    // fix me. put the actual length of lbv data
   {
      m_ErrorCode = 1;
      return eNACK;
   }

   switch(*pb)    // lift typed
   {
      default:
         return eNACK;
      //break;
      case 6:     // lift type from last operation
         break;
      case 14:    // mini
      case 15:    // small slab
      case 16:    // large slab
      case 17:    // dc68
         LBV_Main.bLiftType = *pb;
         break;
   }

   switch(LBV_Main.bLiftType)    // lift typed
   {
      default:
      case 15:    // small slab
         lift_setup.bLiftType = RECORD_MAGIC_SMALL_SLAB;
         //bRisedPwmLimit  = SMAL_SLAB_RISED_PWM_LIMIT;
         break;
      case 14:    // run_about
         lift_setup.bLiftType = RECORD_MAGIC_ELEC1;
         //bRisedPwmLimit  = ELEC1_RISED_PWM_LIMIT;
         break;
      case 16:    // large slab
         lift_setup.bLiftType = RECORD_MAGIC_ELEC3;
         //bRisedPwmLimit  = ELEC3_RISED_PWM_LIMIT;
         break;
      /*case 17:    // dc68
         lift_setup.bLiftType = RECORD_MAGIC_ELEC2;
         bRisedPwmLimit  = ELEC2_RISED_PWM_LIMIT;
         break;*/
   }

   //form lift_setup
   if(!(LABVIEW_REV2 == pLbv->bMagic))
   {
      m_ErrorCode = 2;
      return eNACK;
   }

   lift_setup.bMajor                      = IMAGE_Descr.szName[ 0];
   lift_setup.bMinor                      = IMAGE_Descr.szName[ 1];
   lift_setup.bBrakeDelay                 = pLbv->bBrakeDelay;
   lift_setup.bCoilFaultDetectionPeriod   = pLbv->bCoilFaultDetectionPeriod;
   lift_setup.bSteeringOffDelay           = pLbv->bSteeringOffDelay;
   lift_setup.bDirectionDelay             = pLbv->bDirectionDelay;
   lift_setup.bMotorEnableDelay           = pLbv->bMotorEnableDelay;
   lift_setup.bOverloadStabilizationPeriod = pLbv->bOverloadStabilizationPeriod;

   lift_setup.bSteeringBoostPwm           = pLbv->bSteeringBoostPwm;
   lift_setup.bNeutralSteeringPwm         = pLbv->bNeutralSteeringPwm;
   lift_setup.bChassisLiftUpPwm           = pLbv->bChassisLiftUpPwm;
   lift_setup.bPlatformLiftUpMaxPwm       = pLbv->bPlatformLiftUpMaxPwm;

   lift_setup.bJoystickOffsetCompensation = pLbv->bJoystickOffsetCompensation;
   lift_setup.bJoystickNeutralZone        = pLbv->bJoystickNeutralZone;
   lift_setup.bBatteryLevel1              = pLbv->bBatteryLevel1;
   lift_setup.bBatteryLevel2              = pLbv->bBatteryLevel2;
   lift_setup.bBatteryLevel3              = pLbv->bBatteryLevel3;
   lift_setup.bBatteryLevel4              = pLbv->bBatteryLevel4;
   lift_setup.bBatteryLevel5              = pLbv->bBatteryLevel5;

   lift_setup.bTiltBrakeDelay             = pLbv->bTiltBrakeDelay;
   lift_setup.bLevelBrakeDelay            = pLbv->bLevelBrakeDelay;

   lift_setup.bSpare1                     = pLbv->bSpare1;
   lift_setup.bSpare2                     = pLbv->bSpare2;
   lift_setup.bSpare3                     = pLbv->bSpare3;
   lift_setup.bSpare4                     = pLbv->bSpare4;
   lift_setup.bSpare5                     = pLbv->bSpare5;

   if(!(lift_setup.bBatteryLevel1 > (120 - 100)
        && lift_setup.bBatteryLevel2 > lift_setup.bBatteryLevel1
        && lift_setup.bBatteryLevel3 > lift_setup.bBatteryLevel2
        && lift_setup.bBatteryLevel4 > lift_setup.bBatteryLevel3
        && lift_setup.bBatteryLevel5 > lift_setup.bBatteryLevel4
        && (300 - 100) > lift_setup.bBatteryLevel5))
   {
      m_ErrorCode = 3;
      return eNACK;
   }

   if(lift_setup.bJoystickNeutralZone > 25
      || lift_setup.bJoystickOffsetCompensation > 60

      || lbv_to_setup(&pLbv->drive_fast_curve,
                      &lift_setup.drive_fast_curve,
                      100,
                      lift_setup.bJoystickNeutralZone)
      || lbv_to_setup(&pLbv->drive_rised_curve,
                      &lift_setup.drive_rised_curve,
                      100,
                      lift_setup.bJoystickNeutralZone)
      || lbv_to_setup(&pLbv->lift_up_curve,
                      &lift_setup.lift_up_curve,
                      100,
                      lift_setup.bJoystickNeutralZone)
      //         || lbv_to_setup( &pLbv->steer_fast_curve,
      //                          &lift_setup.steer_fast_curve,
      || lbv_to_setup(&pLbv->drive_slow_curve,
                      &lift_setup.drive_slow_curve,
                      100,
                      lift_setup.bJoystickNeutralZone)
      || lbv_to_setup(&pLbv->steer_rised_curve,
                      &lift_setup.steer_rised_curve,
                      100,
                      lift_setup.bJoystickNeutralZone))

   {
      m_ErrorCode = 4;
      return eNACK;
   }

   if(EEPROM_OK != record_write_verify(lift_setup.bLiftType
                                       , sizeof(struct nvm_lift_setup)
                                       , (UINT8 *)&lift_setup))
   {
      m_ErrorCode = 9;
      return eNACK;
   }

   return eACK;
}


/*******************************************************************************
 *
 * PROCEDURE:    Labview_RestoreDefaults()
 *
 * DESCRIPTION: it copies defaults parameters to eeprom.
 *
 * VARIABLE NAME    R/W DESCRIPTION
 * ---------------- --- --------------------------------------------------------
 ******************************************************************************/


eStatus_t
Labview_RestoreDefaults(void)
{
   UINT8 * pb;
   struct nvm_lift_setup * pSetup;
   //    struct nvm_lift_setup defaultSetup;
   //    int i;

   pb = PACKET_DATA;

   if(!DATA_LENGTH)
   {
      return eNACK;
   }

   switch(*pb)    // lift typed
   {
      default:
         return eNACK;
      //break;
      case 6:     // lift type from last operation
         break;
      case 14:    // mini
      case 15:    // small slab
      case 16:    // large slab
      case 17:    // dc68
         LBV_Main.bLiftType = *pb;
         break;
   }

   switch(LBV_Main.bLiftType)    // lift type
   {
      default:
      case 15:    // small slab
         pSetup = (struct nvm_lift_setup *)&small_slab_setup;
         break;
      case 14:    // mini
         pSetup = (struct nvm_lift_setup *)&electric1_setup;
         break;
      case 16:    // large slab
         pSetup = (struct nvm_lift_setup *)&electric3_setup;
         break;
      /*case 17:    // dc68
         pSetup = (UINT8 *)&electric2_setup;
         break;*/
   }

   //    pb = (UINT8 *)&tempSetup;
   //    for( i = 0; i < sizeof(struct nvm_lift_setup); i++ )
   //    {
   //        *pb = *pSetup;
   //        pb++;
   //        pSetup++;
   //    }
   //
   //    if( (LBV_Main.bLiftType == 14) && (lift_options.fType == LIFT_TYPE_ELEC1) && lift_options.fMotorCtlr_option )
   //    {
   //        tempSetup.lift_up_curve.bPwmPos2 = 19;
   //        tempSetup.lift_up_curve.bPwmPos3 = 25;
   //        tempSetup.lift_up_curve.bPwmPos4 = 33;
   //        tempSetup.lift_up_curve.bPwmPosMax = 43;
   //        tempSetup.lift_up_curve.bPwmPosAdjust = 43;
   //    }

   if(EEPROM_OK != record_write_verify(pSetup->bLiftType, sizeof(struct nvm_lift_setup), (UINT8 *)pSetup))
   {
      return eNACK;
   }

   return eACK;
}

/*******************************************************************************
 *
 * PROCEDURE:    Labview_CheckEeprom()
 *
 * DESCRIPTION: It write 0x00 and 0xFF to EEPROM and read to check.
 *              It return ack for pass, or return nack for fail.
 *
 * VARIABLE NAME    R/W DESCRIPTION
 * ---------------- --- --------------------------------------------------------
 ******************************************************************************/

#define EEPROM_PAGE_SIZE    64

eStatus_t
Labview_CheckEeprom(void)
{
   unsigned int index;
   unsigned char result[EEPROM_PAGE_SIZE];
   unsigned char index2;

   // write 0x00 to all address
   for(index = 0; index < 0x4000; index += EEPROM_PAGE_SIZE)
   {
      if(EEPROM_OK != EE_Write_Byte(index, 0x00, EEPROM_PAGE_SIZE))
      {
         return eNACK;
      }
      delay_mSec(10);
   }
   // read and check from all address
   for(index = 0; index < 0x4000; index += EEPROM_PAGE_SIZE)
   {
      if(EEPROM_OK != EE_Read(index, &result[0], EEPROM_PAGE_SIZE))
      {
         return eNACK;
      }
      for(index2 = 0; index2 < EEPROM_PAGE_SIZE; index2++)
      {
         if(result[index2] != 0x00)
         {
            return eNACK;
         }
      }
   }
   // write 0xFF to all address
   for(index = 0; index < 0x4000; index += EEPROM_PAGE_SIZE)
   {
      if(EEPROM_OK != EE_Write_Byte(index, 0xFF, EEPROM_PAGE_SIZE))
      {
         return eNACK;
      }
      delay_mSec(10);
   }
   // read and check from all address
   for(index = 0; index < 0x4000; index += EEPROM_PAGE_SIZE)
   {
      if(EEPROM_OK != EE_Read(index, &result[0], EEPROM_PAGE_SIZE))
      {
         return eNACK;
      }
      for(index2 = 0; index2 < EEPROM_PAGE_SIZE; index2++)
      {
         if(result[index2] != 0xFF)
         {
            return eNACK;
         }
      }
   }
   return eACK;
}

/*******************************************************************************
 *
 * PROCEDURE:    Labview_CheckDisplay()
 *
 * DESCRIPTION: It light on one segment of display once. The interval is 0.5s.
 *              It return ack for over.
 *
 * VARIABLE NAME    R/W DESCRIPTION
 * ---------------- --- --------------------------------------------------------
 ******************************************************************************/

eStatus_t
Labview_CheckDisplay(void)
{
   unsigned char uc_Display[] = {0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0x40, 0x80};
   unsigned char index;

   // display left LED in turn
   for(index = 0; index < 8; index++)
   {
      Display.field.bSevenLeft = uc_Display[index];
      Display.field.bSevenRight = 0;
      update_leds();
      delay_mSec(500);
   }

   // display left LED in turn
   for(index = 0; index < 8; index++)
   {
      Display.field.bSevenLeft = 0;
      Display.field.bSevenRight = uc_Display[index];
      update_leds();
      delay_mSec(500);
   }

   return eACK;
}








































